obj->impl = NULL;
}
+ if (obj->shape)
+ gdk_region_destroy (obj->shape);
+
+ if (obj->input_shape)
+ gdk_region_destroy (obj->input_shape);
+
if (obj->cursor)
gdk_cursor_unref (obj->cursor);
static void
remove_child_area (GdkWindowObject *private,
GdkWindowObject *until,
+ gboolean for_input,
GdkRegion *region)
{
GdkWindowObject *child;
GdkRegion *child_region;
GdkRectangle r;
GList *l;
+ GdkRegion *shape;
for (l = private->children; l; l = l->next)
{
gdk_region_intersect (child_region, child->shape);
else if (private->window_type == GDK_WINDOW_FOREIGN)
{
- GdkRegion *shape;
shape = _gdk_windowing_window_get_shape ((GdkWindow *)child);
if (shape)
{
gdk_region_destroy (shape);
}
}
+
+ if (for_input)
+ {
+ if (child->input_shape)
+ gdk_region_intersect (child_region, child->input_shape);
+ else if (private->window_type == GDK_WINDOW_FOREIGN)
+ {
+ shape = _gdk_windowing_window_get_input_shape ((GdkWindow *)child);
+ if (shape)
+ {
+ gdk_region_intersect (child_region, shape);
+ gdk_region_destroy (shape);
+ }
+ }
+ }
gdk_region_subtract (region, child_region);
gdk_region_destroy (child_region);
gdk_region_intersect (new_clip, private->parent->clip_region);
/* Remove all overlapping children from parent */
- remove_child_area (private->parent, private, new_clip);
+ remove_child_area (private->parent, private, FALSE, new_clip);
}
/* Convert from parent coords to window coords */
old_clip_region_with_children = private->clip_region_with_children;
private->clip_region_with_children = gdk_region_copy (private->clip_region);
- remove_child_area (private, NULL, private->clip_region_with_children);
+ remove_child_area (private, NULL, FALSE, private->clip_region_with_children);
if (clip_region_changed ||
!gdk_region_equal (private->clip_region_with_children, old_clip_region_with_children))
{
GDK_WINDOW_IMPL_GET_IFACE (private->impl)->shape_combine_region ((GdkWindow *)private, private->clip_region, 0, 0);
}
-
-
+
if (recalculate_siblings &&
private->parent != NULL &&
GDK_WINDOW_TYPE (private->parent) != GDK_WINDOW_ROOT)
private->impl = old_impl;
change_impl (private, new_impl);
+
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->input_shape_combine_region ((GdkWindow *)private, private->input_shape, 0, 0);
}
else
{
r.height = private->height;
region = gdk_region_rectangle (&r);
- remove_child_area (private, NULL, region);
+ remove_child_area (private, NULL, FALSE, region);
if (merge && private->shape)
gdk_region_subtract (region, private->shape);
do_child_shapes (window, TRUE);
}
+/**
+ * gdk_window_input_shape_combine_mask:
+ * @window: a #GdkWindow
+ * @mask: shape mask
+ * @x: X position of shape mask with respect to @window
+ * @y: Y position of shape mask with respect to @window
+ *
+ * Like gdk_window_shape_combine_mask(), but the shape applies
+ * only to event handling. Mouse events which happen while
+ * the pointer position corresponds to an unset bit in the
+ * mask will be passed on the window below @window.
+ *
+ * An input shape is typically used with RGBA windows.
+ * The alpha channel of the window defines which pixels are
+ * invisible and allows for nicely antialiased borders,
+ * and the input shape controls where the window is
+ * "clickable".
+ *
+ * On the X11 platform, this requires version 1.1 of the
+ * shape extension.
+ *
+ * On the Win32 platform, this functionality is not present and the
+ * function does nothing.
+ *
+ * Since: 2.10
+ */
+void
+gdk_window_input_shape_combine_mask (GdkWindow *window,
+ GdkBitmap *mask,
+ gint x,
+ gint y)
+{
+ GdkWindowObject *private;
+ GdkRegion *region;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ private = (GdkWindowObject *) window;
+
+ region = _gdk_windowing_get_shape_for_mask (mask);
+
+ gdk_window_input_shape_combine_region (window,
+ region,
+ x, y);
+
+ gdk_region_destroy (region);
+}
+
+/**
+ * gdk_window_input_shape_combine_region:
+ * @window: a #GdkWindow
+ * @shape_region: region of window to be non-transparent
+ * @offset_x: X position of @shape_region in @window coordinates
+ * @offset_y: Y position of @shape_region in @window coordinates
+ *
+ * Like gdk_window_shape_combine_region(), but the shape applies
+ * only to event handling. Mouse events which happen while
+ * the pointer position corresponds to an unset bit in the
+ * mask will be passed on the window below @window.
+ *
+ * An input shape is typically used with RGBA windows.
+ * The alpha channel of the window defines which pixels are
+ * invisible and allows for nicely antialiased borders,
+ * and the input shape controls where the window is
+ * "clickable".
+ *
+ * On the X11 platform, this requires version 1.1 of the
+ * shape extension.
+ *
+ * On the Win32 platform, this functionality is not present and the
+ * function does nothing.
+ *
+ * Since: 2.10
+ */
+void
+gdk_window_input_shape_combine_region (GdkWindow *window,
+ const GdkRegion *shape_region,
+ gint offset_x,
+ gint offset_y)
+{
+ GdkWindowObject *private;
+
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ private = (GdkWindowObject *) window;
+
+ if (GDK_WINDOW_DESTROYED (window))
+ return;
+
+ if (private->input_shape)
+ gdk_region_destroy (private->input_shape);
+
+ if (shape_region)
+ {
+ private->input_shape = gdk_region_copy (shape_region);
+ gdk_region_offset (private->shape, offset_x, offset_y);
+ }
+ else
+ private->input_shape = NULL;
+
+ if (gdk_window_has_impl (private))
+ GDK_WINDOW_IMPL_GET_IFACE (private->impl)->input_shape_combine_region ((GdkWindow *)private, private->input_shape, 0, 0);
+
+ /* Pointer may have e.g. moved outside window due to the input mask change */
+ _gdk_syntesize_crossing_events_for_geometry_change (window);
+}
+
+static void
+do_child_input_shapes (GdkWindow *window,
+ gboolean merge)
+{
+ GdkWindowObject *private;
+ GdkRectangle r;
+ GdkRegion *region;
+
+ private = (GdkWindowObject *) window;
+
+ r.x = 0;
+ r.y = 0;
+ r.width = private->width;
+ r.height = private->height;
+
+ region = gdk_region_rectangle (&r);
+ remove_child_area (private, NULL, TRUE, region);
+
+ if (merge && private->shape)
+ gdk_region_subtract (region, private->shape);
+ if (merge && private->input_shape)
+ gdk_region_subtract (region, private->input_shape);
+
+ gdk_window_input_shape_combine_region (window, region, 0, 0);
+}
+
+
+/**
+ * gdk_window_set_child_input_shapes:
+ * @window: a #GdkWindow
+ *
+ * Sets the input shape mask of @window to the union of input shape masks
+ * for all children of @window, ignoring the input shape mask of @window
+ * itself. Contrast with gdk_window_merge_child_input_shapes() which includes
+ * the input shape mask of @window in the masks to be merged.
+ *
+ * Since: 2.10
+ **/
+void
+gdk_window_set_child_input_shapes (GdkWindow *window)
+{
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ do_child_input_shapes (window, FALSE);
+}
+
+/**
+ * gdk_window_merge_child_input_shapes:
+ * @window: a #GdkWindow
+ *
+ * Merges the input shape masks for any child windows into the
+ * input shape mask for @window. i.e. the union of all input masks
+ * for @window and its children will become the new input mask
+ * for @window. See gdk_window_input_shape_combine_mask().
+ *
+ * This function is distinct from gdk_window_set_child_input_shapes()
+ * because it includes @window's input shape mask in the set of
+ * shapes to be merged.
+ *
+ * Since: 2.10
+ **/
+void
+gdk_window_merge_child_input_shapes (GdkWindow *window)
+{
+ g_return_if_fail (GDK_IS_WINDOW (window));
+
+ do_child_input_shapes (window, TRUE);
+}
+
/**
* gdk_window_set_static_gravities:
y >= 0 && y < window->height &&
(window->shape == NULL ||
gdk_region_point_in (window->shape,
+ x, y)) &&
+ (window->input_shape == NULL ||
+ gdk_region_point_in (window->input_shape,
x, y));
}
XFree (old_windows);
}
-/**
- * gdk_window_input_shape_combine_mask:
- * @window: a #GdkWindow
- * @mask: shape mask
- * @x: X position of shape mask with respect to @window
- * @y: Y position of shape mask with respect to @window
- *
- * Like gdk_window_shape_combine_mask(), but the shape applies
- * only to event handling. Mouse events which happen while
- * the pointer position corresponds to an unset bit in the
- * mask will be passed on the window below @window.
- *
- * An input shape is typically used with RGBA windows.
- * The alpha channel of the window defines which pixels are
- * invisible and allows for nicely antialiased borders,
- * and the input shape controls where the window is
- * "clickable".
- *
- * On the X11 platform, this requires version 1.1 of the
- * shape extension.
- *
- * On the Win32 platform, this functionality is not present and the
- * function does nothing.
- *
- * Since: 2.10
- */
-void
-gdk_window_input_shape_combine_mask (GdkWindow *window,
- GdkBitmap *mask,
- gint x,
- gint y)
-{
-#ifdef ShapeInput
- do_shape_combine_mask (window, mask, x, y, ShapeInput);
-#endif
-}
-
-
static inline void
do_shape_combine_region (GdkWindow *window,
const GdkRegion *shape_region,
do_shape_combine_region (window, shape_region, offset_x, offset_y, ShapeBounding);
}
-/**
- * gdk_window_input_shape_combine_region:
- * @window: a #GdkWindow
- * @shape_region: region of window to be non-transparent
- * @offset_x: X position of @shape_region in @window coordinates
- * @offset_y: Y position of @shape_region in @window coordinates
- *
- * Like gdk_window_shape_combine_region(), but the shape applies
- * only to event handling. Mouse events which happen while
- * the pointer position corresponds to an unset bit in the
- * mask will be passed on the window below @window.
- *
- * An input shape is typically used with RGBA windows.
- * The alpha channel of the window defines which pixels are
- * invisible and allows for nicely antialiased borders,
- * and the input shape controls where the window is
- * "clickable".
- *
- * On the X11 platform, this requires version 1.1 of the
- * shape extension.
- *
- * On the Win32 platform, this functionality is not present and the
- * function does nothing.
- *
- * Since: 2.10
- */
-void
-gdk_window_input_shape_combine_region (GdkWindow *window,
- const GdkRegion *shape_region,
- gint offset_x,
- gint offset_y)
+static void
+gdk_window_x11_input_shape_combine_region (GdkWindow *window,
+ const GdkRegion *shape_region,
+ gint offset_x,
+ gint offset_y)
{
#ifdef ShapeInput
do_shape_combine_region (window, shape_region, offset_x, offset_y, ShapeInput);
gdk_window_set_mwm_hints (window, &hints);
}
-#ifdef HAVE_SHAPE_EXT
-
-/*
- * propagate the shapes from all child windows of a GDK window to the parent
- * window. Shamelessly ripped from Enlightenment's code
- *
- * - Raster
- */
-struct _gdk_span
-{
- gint start;
- gint end;
- struct _gdk_span *next;
-};
-
-static void
-gdk_add_to_span (struct _gdk_span **s,
- gint x,
- gint xx)
-{
- struct _gdk_span *ptr1, *ptr2, *noo, *ss;
- gchar spanning;
-
- ptr2 = NULL;
- ptr1 = *s;
- spanning = 0;
- ss = NULL;
- /* scan the spans for this line */
- while (ptr1)
- {
- /* -- -> new span */
- /* == -> existing span */
- /* ## -> spans intersect */
- /* if we are in the middle of spanning the span into the line */
- if (spanning)
- {
- /* case: ---- ==== */
- if (xx < ptr1->start - 1)
- {
- /* ends before next span - extend to here */
- ss->end = xx;
- return;
- }
- /* case: ----##=== */
- else if (xx <= ptr1->end)
- {
- /* crosses into next span - delete next span and append */
- ss->end = ptr1->end;
- ss->next = ptr1->next;
- g_free (ptr1);
- return;
- }
- /* case: ---###--- */
- else
- {
- /* overlaps next span - delete and keep checking */
- ss->next = ptr1->next;
- g_free (ptr1);
- ptr1 = ss;
- }
- }
- /* otherwise havent started spanning it in yet */
- else
- {
- /* case: ---- ==== */
- if (xx < ptr1->start - 1)
- {
- /* insert span here in list */
- noo = g_malloc (sizeof (struct _gdk_span));
-
- if (noo)
- {
- noo->start = x;
- noo->end = xx;
- noo->next = ptr1;
- if (ptr2)
- ptr2->next = noo;
- else
- *s = noo;
- }
- return;
- }
- /* case: ----##=== */
- else if ((x < ptr1->start) && (xx <= ptr1->end))
- {
- /* expand this span to the left point of the new one */
- ptr1->start = x;
- return;
- }
- /* case: ===###=== */
- else if ((x >= ptr1->start) && (xx <= ptr1->end))
- {
- /* throw the span away */
- return;
- }
- /* case: ---###--- */
- else if ((x < ptr1->start) && (xx > ptr1->end))
- {
- ss = ptr1;
- spanning = 1;
- ptr1->start = x;
- ptr1->end = xx;
- }
- /* case: ===##---- */
- else if ((x >= ptr1->start) && (x <= ptr1->end + 1) && (xx > ptr1->end))
- {
- ss = ptr1;
- spanning = 1;
- ptr1->end = xx;
- }
- /* case: ==== ---- */
- /* case handled by next loop iteration - first case */
- }
- ptr2 = ptr1;
- ptr1 = ptr1->next;
- }
- /* it started in the middle but spans beyond your current list */
- if (spanning)
- {
- ptr2->end = xx;
- return;
- }
- /* it does not start inside a span or in the middle, so add it to the end */
- noo = g_malloc (sizeof (struct _gdk_span));
-
- if (noo)
- {
- noo->start = x;
- noo->end = xx;
- if (ptr2)
- {
- noo->next = ptr2->next;
- ptr2->next = noo;
- }
- else
- {
- noo->next = NULL;
- *s = noo;
- }
- }
- return;
-}
-
static GdkRegion *
xwindow_get_shape (Display *xdisplay,
- Window window)
+ Window window,
+ gint shape_type)
{
GdkRegion *shape;
GdkRectangle *rl;
#if defined(HAVE_SHAPE_EXT)
xrl = XShapeGetRectangles (xdisplay,
window,
- ShapeBounding, &rn, &ord);
-
+ shape_type, &rn, &ord);
+
if (rn == 0)
return gdk_region_new (); /* Empty */
ShapeSet);
region = xwindow_get_shape (GDK_DISPLAY_XDISPLAY (display),
- window);
+ window, ShapeBounding);
XDestroyWindow (GDK_DISPLAY_XDISPLAY (display),
window);
if (!GDK_WINDOW_DESTROYED (window) &&
gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window)))
return xwindow_get_shape (GDK_WINDOW_XDISPLAY (window),
- GDK_WINDOW_XID (window));
+ GDK_WINDOW_XID (window), ShapeBounding);
#endif
return NULL;
}
-static void
-gdk_add_rectangles (Display *disp,
- Window win,
- struct _gdk_span **spans,
- gint basew,
- gint baseh,
- gint x,
- gint y)
-{
- gint a, k;
- gint x1, y1, x2, y2;
- gint rn, ord;
- XRectangle *rl;
-
- rl = XShapeGetRectangles (disp, win, ShapeBounding, &rn, &ord);
- if (rl)
- {
- /* go through all clip rects in this window's shape */
- for (k = 0; k < rn; k++)
- {
- /* for each clip rect, add it to each line's spans */
- x1 = x + rl[k].x;
- x2 = x + rl[k].x + (rl[k].width - 1);
- y1 = y + rl[k].y;
- y2 = y + rl[k].y + (rl[k].height - 1);
- if (x1 < 0)
- x1 = 0;
- if (y1 < 0)
- y1 = 0;
- if (x2 >= basew)
- x2 = basew - 1;
- if (y2 >= baseh)
- y2 = baseh - 1;
- for (a = y1; a <= y2; a++)
- {
- if ((x2 - x1) >= 0)
- gdk_add_to_span (&spans[a], x1, x2);
- }
- }
- XFree (rl);
- }
-}
-
-static void
-gdk_propagate_shapes (Display *disp,
- Window win,
- gboolean merge,
- int shape)
-{
- Window rt, par, *list = NULL;
- gint i, j, num = 0, num_rects = 0;
- gint x, y, contig;
- guint w, h, d;
- gint baseh, basew;
- XRectangle *rects = NULL;
- struct _gdk_span **spans = NULL, *ptr1, *ptr2, *ptr3;
- XWindowAttributes xatt;
-
- XGetGeometry (disp, win, &rt, &x, &y, &w, &h, &d, &d);
- if (h <= 0)
- return;
- basew = w;
- baseh = h;
- spans = g_malloc (sizeof (struct _gdk_span *) * h);
-
- for (i = 0; i < h; i++)
- spans[i] = NULL;
- XQueryTree (disp, win, &rt, &par, &list, (unsigned int *)&num);
- if (list)
- {
- /* go through all child windows and create/insert spans */
- for (i = 0; i < num; i++)
- {
- if (XGetWindowAttributes (disp, list[i], &xatt) && (xatt.map_state != IsUnmapped))
- if (XGetGeometry (disp, list[i], &rt, &x, &y, &w, &h, &d, &d))
- gdk_add_rectangles (disp, list[i], spans, basew, baseh, x, y);
- }
- if (merge)
- gdk_add_rectangles (disp, win, spans, basew, baseh, x, y);
-
- /* go through the spans list and build a list of rects */
- rects = g_malloc (sizeof (XRectangle) * 256);
- num_rects = 0;
- for (i = 0; i < baseh; i++)
- {
- ptr1 = spans[i];
- /* go through the line for all spans */
- while (ptr1)
- {
- rects[num_rects].x = ptr1->start;
- rects[num_rects].y = i;
- rects[num_rects].width = ptr1->end - ptr1->start + 1;
- rects[num_rects].height = 1;
- j = i + 1;
- /* if there are more lines */
- contig = 1;
- /* while contigous rects (same start/end coords) exist */
- while ((contig) && (j < baseh))
- {
- /* search next line for spans matching this one */
- contig = 0;
- ptr2 = spans[j];
- ptr3 = NULL;
- while (ptr2)
- {
- /* if we have an exact span match set contig */
- if ((ptr2->start == ptr1->start) &&
- (ptr2->end == ptr1->end))
- {
- contig = 1;
- /* remove the span - not needed */
- if (ptr3)
- {
- ptr3->next = ptr2->next;
- g_free (ptr2);
- ptr2 = NULL;
- }
- else
- {
- spans[j] = ptr2->next;
- g_free (ptr2);
- ptr2 = NULL;
- }
- break;
- }
- /* gone past the span point no point looking */
- else if (ptr2->start < ptr1->start)
- break;
- if (ptr2)
- {
- ptr3 = ptr2;
- ptr2 = ptr2->next;
- }
- }
- /* if a contiguous span was found increase the rect h */
- if (contig)
- {
- rects[num_rects].height++;
- j++;
- }
- }
- /* up the rect count */
- num_rects++;
- /* every 256 new rects increase the rect array */
- if ((num_rects % 256) == 0)
- rects = g_realloc (rects, sizeof (XRectangle) * (num_rects + 256));
- ptr1 = ptr1->next;
- }
- }
- /* set the rects as the shape mask */
- if (rects)
- {
- XShapeCombineRectangles (disp, win, shape, 0, 0, rects, num_rects,
- ShapeSet, YXSorted);
- g_free (rects);
- }
- XFree (list);
- }
- /* free up all the spans we made */
- for (i = 0; i < baseh; i++)
- {
- ptr1 = spans[i];
- while (ptr1)
- {
- ptr2 = ptr1;
- ptr1 = ptr1->next;
- g_free (ptr2);
- }
- }
- g_free (spans);
-}
-
-#endif /* HAVE_SHAPE_EXT */
-
-static inline void
-do_child_shapes (GdkWindow *window,
- gboolean merge)
-{
-#ifdef HAVE_SHAPE_EXT
- if (!GDK_WINDOW_DESTROYED (window) &&
- gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window)))
- {
- gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window),
- GDK_WINDOW_XID (window),
- merge,
- ShapeBounding);
- }
-#endif
-}
-
-static void
-gdk_window_x11_set_child_shapes (GdkWindow *window)
-{
- do_child_shapes (window, FALSE);
-}
-
-static void
-gdk_window_x11_merge_child_shapes (GdkWindow *window)
-{
- do_child_shapes (window, TRUE);
-}
-
-static inline void
-do_child_input_shapes (GdkWindow *window,
- gboolean merge)
+GdkRegion *
+_gdk_windowing_window_get_input_shape (GdkWindow *window)
{
-#if defined(HAVE_SHAPE_EXT) && defined(ShapeInput)
+#if defined(HAVE_SHAPE_EXT)
if (!GDK_WINDOW_DESTROYED (window) &&
gdk_display_supports_shapes (GDK_WINDOW_DISPLAY (window)))
- {
- gdk_propagate_shapes (GDK_WINDOW_XDISPLAY (window),
- GDK_WINDOW_XID (window),
- merge,
- ShapeInput);
- }
+ return xwindow_get_shape (GDK_WINDOW_XDISPLAY (window),
+ GDK_WINDOW_XID (window),
+ ShapeInput);
#endif
-}
-
-/**
- * gdk_window_set_child_input_shapes:
- * @window: a #GdkWindow
- *
- * Sets the input shape mask of @window to the union of input shape masks
- * for all children of @window, ignoring the input shape mask of @window
- * itself. Contrast with gdk_window_merge_child_input_shapes() which includes
- * the input shape mask of @window in the masks to be merged.
- *
- * Since: 2.10
- **/
-void
-gdk_window_set_child_input_shapes (GdkWindow *window)
-{
- g_return_if_fail (GDK_IS_WINDOW (window));
-
- do_child_input_shapes (window, FALSE);
-}
-/**
- * gdk_window_merge_child_input_shapes:
- * @window: a #GdkWindow
- *
- * Merges the input shape masks for any child windows into the
- * input shape mask for @window. i.e. the union of all input masks
- * for @window and its children will become the new input mask
- * for @window. See gdk_window_input_shape_combine_mask().
- *
- * This function is distinct from gdk_window_set_child_input_shapes()
- * because it includes @window's input shape mask in the set of
- * shapes to be merged.
- *
- * Since: 2.10
- **/
-void
-gdk_window_merge_child_input_shapes (GdkWindow *window)
-{
- g_return_if_fail (GDK_IS_WINDOW (window));
-
- do_child_input_shapes (window, TRUE);
+ return NULL;
}
-
static void
gdk_window_set_static_bit_gravity (GdkWindow *window,
gboolean on)
iface->get_origin = gdk_window_x11_get_origin;
iface->get_deskrelative_origin = gdk_window_x11_get_deskrelative_origin;
iface->shape_combine_region = gdk_window_x11_shape_combine_region;
- iface->set_child_shapes = gdk_window_x11_set_child_shapes;
- iface->merge_child_shapes = gdk_window_x11_merge_child_shapes;
+ iface->input_shape_combine_region = gdk_window_x11_input_shape_combine_region;
iface->set_static_gravities = gdk_window_x11_set_static_gravities;
iface->queue_antiexpose = _gdk_x11_window_queue_antiexpose;
iface->queue_translation = _gdk_x11_window_queue_translation;